//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//
// (C) Copyright 2006 Marvell International Ltd.
// All Rights Reserved
//
/******************************************************************************
**
**  COPYRIGHT (C) 2001, 2002 Intel Corporation.
**
**  This software as well as the software described in it is furnished under
**  license and may only be used or copied in accordance with the terms of the
**  license. The information in this file is furnished for informational use
**  only, is subject to change without notice, and should not be construed as
**  a commitment by Intel Corporation. Intel Corporation assumes no
**  responsibility or liability for any errors or inaccuracies that may appear
**  in this document or any software that may be provided in association with
**  this document. 
**  Except as permitted by such license, no part of this document may be 
**  reproduced, stored in a retrieval system, or transmitted in any form or by
**  any means without the express written consent of Intel Corporation. 
**
**  FILENAME: dmawince.c
**
**  PURPOSE: Contains all WinCE OS specific functions for DMA Controller Engine 
**           access and control
**                  
******************************************************************************/

#include <windows.h>
#include "monahans.h"
#include <string.h>
#include <stdio.h>
#include <tchar.h>
#include <ceddk.h>

#include <nkintr.h>
#include "xllp_intc.h"
#include "xllp_dmac.h"
#include "dmawince.h"

#ifndef ZONE_ERROR
#define ZONE_ERROR 1
#endif

static    DWORD dma_sys_intr;

//
// DMA IST routine
//
INT WINAPI DmacIntrThread(void);


//
// Externs
//

// pkdbug. Not needed...extern void     XllpDmacHwInit();

volatile DMA_GLOBALS *pDMAGlobals = NULL;
volatile P_XLLP_DMAC_T	pDmacHandle = NULL;
HANDLE		hFirstTime;

#define DMA_CHANNEL_0  _T("DMA_CHANNEL_0")
#define DMA_CHANNEL_1  _T("DMA_CHANNEL_1")
#define DMA_CHANNEL_2  _T("DMA_CHANNEL_2")
#define DMA_CHANNEL_3  _T("DMA_CHANNEL_3")
#define DMA_CHANNEL_4  _T("DMA_CHANNEL_4")
#define DMA_CHANNEL_5  _T("DMA_CHANNEL_5")
#define DMA_CHANNEL_6  _T("DMA_CHANNEL_6")
#define DMA_CHANNEL_7  _T("DMA_CHANNEL_7")
#define DMA_CHANNEL_8  _T("DMA_CHANNEL_8")
#define DMA_CHANNEL_9  _T("DMA_CHANNEL_9")
#define DMA_CHANNEL_10  _T("DMA_CHANNEL_10")
#define DMA_CHANNEL_11  _T("DMA_CHANNEL_11")
#define DMA_CHANNEL_12  _T("DMA_CHANNEL_12")
#define DMA_CHANNEL_13  _T("DMA_CHANNEL_13")
#define DMA_CHANNEL_14  _T("DMA_CHANNEL_14")
#define DMA_CHANNEL_15  _T("DMA_CHANNEL_15")
#define DMA_CHANNEL_16  _T("DMA_CHANNEL_16")
#define DMA_CHANNEL_17  _T("DMA_CHANNEL_17")
#define DMA_CHANNEL_18  _T("DMA_CHANNEL_18")
#define DMA_CHANNEL_19  _T("DMA_CHANNEL_19")
#define DMA_CHANNEL_20  _T("DMA_CHANNEL_20")
#define DMA_CHANNEL_21  _T("DMA_CHANNEL_21")
#define DMA_CHANNEL_22  _T("DMA_CHANNEL_22")
#define DMA_CHANNEL_23  _T("DMA_CHANNEL_23")
#define DMA_CHANNEL_24  _T("DMA_CHANNEL_24")
#define DMA_CHANNEL_25  _T("DMA_CHANNEL_25")
#define DMA_CHANNEL_26  _T("DMA_CHANNEL_26")
#define DMA_CHANNEL_27  _T("DMA_CHANNEL_27")
#define DMA_CHANNEL_28  _T("DMA_CHANNEL_28")
#define DMA_CHANNEL_29  _T("DMA_CHANNEL_29")
#define DMA_CHANNEL_30  _T("DMA_CHANNEL_30")
#define DMA_CHANNEL_31  _T("DMA_CHANNEL_31")

// pkdebug - Start ?? Should XLLP_xxx items be changed to GDE_xxx  ??

/**
 * Channel priority sets
 **/
const XLLP_DMAC_CHANNEL_T aPrioritySetCount = 8;
const XLLP_DMAC_CHANNEL_T ChannelPriorityHigh[]=
{
    XLLP_DMAC_CHANNEL_0,
    XLLP_DMAC_CHANNEL_1,
    XLLP_DMAC_CHANNEL_2,
    XLLP_DMAC_CHANNEL_3,
    XLLP_DMAC_CHANNEL_16,
    XLLP_DMAC_CHANNEL_17,
    XLLP_DMAC_CHANNEL_18,
    XLLP_DMAC_CHANNEL_19
};    
const XLLP_DMAC_CHANNEL_T ChannelPriorityMedium[]=
{
    XLLP_DMAC_CHANNEL_4,
    XLLP_DMAC_CHANNEL_5,
    XLLP_DMAC_CHANNEL_6,
    XLLP_DMAC_CHANNEL_7,
    XLLP_DMAC_CHANNEL_20,
    XLLP_DMAC_CHANNEL_21,
    XLLP_DMAC_CHANNEL_22,
    XLLP_DMAC_CHANNEL_23
};    
const XLLP_DMAC_CHANNEL_T ChannelPriorityLow[]=
{
    XLLP_DMAC_CHANNEL_8,
    XLLP_DMAC_CHANNEL_9,
    XLLP_DMAC_CHANNEL_10,
    XLLP_DMAC_CHANNEL_11,
    XLLP_DMAC_CHANNEL_24,
    XLLP_DMAC_CHANNEL_25,
    XLLP_DMAC_CHANNEL_26,
    XLLP_DMAC_CHANNEL_27
};    
const XLLP_DMAC_CHANNEL_T ChannelPriorityLowest[]=
{
    XLLP_DMAC_CHANNEL_12,
    XLLP_DMAC_CHANNEL_13,
    XLLP_DMAC_CHANNEL_14,
    XLLP_DMAC_CHANNEL_15,
    XLLP_DMAC_CHANNEL_28,
    XLLP_DMAC_CHANNEL_29,
    XLLP_DMAC_CHANNEL_30,
    XLLP_DMAC_CHANNEL_31
};    

// pkdebug - Stop  ?? Should XLLP_xxx items be changed to GDE_xxx  ??


//******************************************************************************
//
// Function Name: DllEntry
//
// Description: Function called at dll load time and whenever a process/thread
//              attaches to the dll.
//  			   
//  
// Input Arguments:
//	    hInstDLL:       Instance handle..specifies base address of dll
//      Op:             Operation code
//      lpvReserved:    Reserved
//	                 
// Output Arguments:
//  	
//
// Return Value: 
//	    TRUE:   if Ok to load the dll
//      FALSE:  otherwise
//
// Notes:
//
//*******************************************************************************
BOOL __stdcall DllEntry 
(
    HANDLE  hinstDLL,
    DWORD   Op,
    LPVOID  lpvReserved
)
{  
    //
    // Ref count of processes attaching to DMA library
    //
    static unsigned long processCount=0;

    switch (Op) 
	{

        case DLL_PROCESS_ATTACH :
			++processCount;
			//RETAILMSG(1,(TEXT("DmaDllEntry Proc Attach: 0x%X\r\n"),processCount));
			//NKDbgPrintfW(TEXT("\r\nDMA Engine Loaded -- Process...\r\n"));
            break;

        case DLL_PROCESS_DETACH :
			--processCount;
			//RETAILMSG(1,(TEXT("DmaDllEntry Proc Detach: 0x%X\r\n"),processCount));
            break;
            
        case DLL_THREAD_DETACH :
			//--z;
			//RETAILMSG(1,(TEXT("DmaDllEntry Thrd Detach: 0x%X\r\n"),z));			
            break; 
            
        case DLL_THREAD_ATTACH :
			//++z;
			//RETAILMSG(1,(TEXT("DmaDllEntry Thread Attach: 0x%X\r\n"),processCount));
			//NKDbgPrintfW(TEXT("DMA Engine, Thread Attach...\r\n"));
			
            break;
            
        default :
            break;
    }

	return TRUE;
}


//******************************************************************************
//
//	Function Name: GDE_Init()
//
//	Other STream Interface functions stubbed.
//
//
//******************************************************************************
DWORD	GDE_Init(DWORD p1, DWORD p2)
{
	HANDLE				hSharedMap_init;

	// Initialize the DMA system.
	NKDbgPrintfW(TEXT("GDE_Init In = %x, %x...\r\n"), p1, p2);
	// Memory mapped file for sharing DMA Globals information.
	hSharedMap_init = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
									0, sizeof(DMA_GLOBALS), GDE_SHARED_FILENAME );
	if(!hSharedMap_init)
	{
		NKDbgPrintfW(TEXT("GDE_Init. No MemMap File. \r\n"));
		return 0; //  GDE failed to run.
	}

	// Get a valid process pointer to the memory mapper buffer.
	pDMAGlobals = (DMA_GLOBALS *)MapViewOfFile( hSharedMap_init, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
	// Initialize GDE for this process.
	if( NULL == GdeDmacInit() )
	{
		return 0;   // Failed.
	}

	// Exit
	NKDbgPrintfW(TEXT("GDE_Init Done...\r\n"));
	return 1;   // Use non-zero to indicate success.
} 

//*******************************************
//
//	Stubs
//
//*******************************************

XLLP_BOOL_T GDE_Deinit(DWORD p1)
{
	//NKDbgPrintfW(TEXT("GDE_Deinit..."));
		return XLLP_TRUE;
} 
//*******************************************
DWORD GDE_Open(DWORD P1, DWORD P2, DWORD P3 )
{
	//NKDbgPrintfW(TEXT("GDE_Open..."));
	return 1;
}
//*******************************************
BOOL GDE_Close( DWORD p1)
{
	//NKDbgPrintfW(TEXT("GDE_Close..."));
	return 1;
}
//*******************************************
BOOL GDE_IOControl(
  DWORD hOpenContext,
  DWORD dwCode,
  PBYTE pBufIn,
  DWORD dwLenIn,
  PBYTE pBufOut,
  DWORD dwLenOut,
  PDWORD pdwActualOut 
			)
{
	//NKDbgPrintfW(TEXT("GDE_IOControl..."));
	return 1;
}
//*******************************************
DWORD GDE_Read(
  DWORD hOpenContext,
  LPVOID pBuffer,
  DWORD Count 
			)
{
	//NKDbgPrintfW(TEXT("GDE_Read..."));
	return 1;
}
//*******************************************
DWORD GDE_Write(
  DWORD hOpenContext,
  LPCVOID pBuffer,
  DWORD Count 
			)
{
	//NKDbgPrintfW(TEXT("GDE_Write..."));
	return 1;
}
//*******************************************
DWORD GDE_Seek(
  DWORD hOpenContext,
  long Amount,
  WORD Type 
		)
{
	//NKDbgPrintfW(TEXT("GDE_Seek..."));
	return 1;
}
//*******************************************
void GDE_PowerUp(
  DWORD hDeviceContext 
		)
{
	//NKDbgPrintfW(TEXT("GDE_PowerUp..."));
	return;
}
//*******************************************
void GDE_PowerDown(
  DWORD hDeviceContext 
		)
{
	//NKDbgPrintfW(TEXT("GDE_PowerDown..."));
	return;
}
//*******************************************
	

//******************************************************************************
//
// Function Name: GdeDmacInit
//
// Description: Function called to initialize this dll
//              Creates DMA register mapping, sets up DMA IST and initializes hardware
//  			   
//  
// Input Arguments:
//	
//	                 
// Output Arguments:
//  	
//
// Return Value: 
//	TRUE:       when successful
//  FALSE:      otherwise
//
// Notes:
//
//*******************************************************************************
P_XLLP_DMAC_T	GdeDmacInit
(
)
{
    PHYSICAL_ADDRESS RegPA;
    XLLP_UINT32_T i;
    HANDLE hSharedMap;
    DWORD dma_irq = IRQ_DMAC;
    int status;
 
	// Setup the global memory needed by Gde. Use the memory mapped file mechanism.

	if (pDMAGlobals == NULL)
	{
		// Memory mapped file for sharing DMA Globals information.
		hSharedMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
										0, sizeof(DMA_GLOBALS), GDE_SHARED_FILENAME );
		// Memory mapped file should exist from init in GDE_Init() .
		if( ERROR_ALREADY_EXISTS != GetLastError() )
		{
			NKDbgPrintfW(TEXT(" GdeDmacInit. No existing MemMapFile . \r\n"));
			return NULL;	// DMA failed to intilize correctly.
		}
		// Get a valid process pointer to the buffer mapped above.
		pDMAGlobals = (DMA_GLOBALS *)MapViewOfFile( hSharedMap, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
		if( !pDMAGlobals )
		{
			NKDbgPrintfW(TEXT( "GdeDmacInit. MapViewOfFile failed . \r\n"));
			return NULL;	// DMA failed to intilize correctly.
		}

	}

	// Get a pointer to the DMAC registers.

	if (pDmacHandle == NULL)
	{
            RegPA.QuadPart = MONAHANS_BASE_REG_PA_DMAC;
            pDmacHandle = (P_XLLP_DMAC_T) MmMapIoSpace(RegPA, sizeof(XLLP_DMAC_T), FALSE);

            if (pDmacHandle == NULL)
            {
            	NKDbgPrintfW(TEXT("GdeDmacInit. Failed, pDmacHandle is NULL... \r\n"));  // pkdebug.
            	return NULL;
            }
	    NKDbgPrintfW(TEXT("GdeDmacInit. Success. sizeof(XLLP_DMAC_T) = %d \r\n"), sizeof(XLLP_DMAC_T));  // pkdebug.
	}


    //
    // Check for first time initialization Object.
    //  Note -- Other drivers can use this named object to check for and/or wait for
	//			GDE setup to complete.
	//
	hFirstTime = CreateEvent(NULL, TRUE, FALSE, GDE_FIRST_TIME_CHECK);  // Null, Manual, Set, Named.
	if(!hFirstTime)
	{
		NKDbgPrintfW(TEXT("XllpDmacInit. Failed to create FirstTime Object. \r\n"));
		return NULL;	// DMA failed to intilize correctly.
	}
	// GDE Setup successfully occured if the object already exists.
	if( ERROR_ALREADY_EXISTS == GetLastError() )
	{
		return pDmacHandle;	// First Time initialization already done.
	}


    //
    // Do all the only one time initialization

	if (XLLP_STATUS_SUCCESS != XllpDmacInit( pDmacHandle ) )
	{
		NKDbgPrintfW(TEXT("XllpDmacInit Failed. \r\n"));
		return NULL;	// DMA failed to intilize correctly.
	}

    // Initialize the channel allocation array.
    //
    for(i=0;i<32;++i)
        pDMAGlobals->pArrayChannel[i] = 0;

    status = KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &dma_irq, sizeof(UINT32), 
                             &dma_sys_intr, sizeof(UINT32), NULL);
    if (status != TRUE)
    {
        RETAILMSG(1, (TEXT("DMA: Error obtaining dma SYSINTR value %d!\n"), status));
        return FALSE;
    }
    

    pDMAGlobals->gDmacIntrEvent =  CreateEvent(NULL, FALSE, FALSE, NULL);
    //
    // Create DMA IST
    // This thread will handle all DMA interrupts and be responsible for calling appropriate
    // second level handlers.
    // 
    if (!(InterruptInitialize(dma_sys_intr, pDMAGlobals->gDmacIntrEvent, NULL, 0))) 
    {        
        RETAILMSG(1,(TEXT("DMAC: Interrupt initialization failed IID = %d...\r\n"), dma_sys_intr));
        return NULL;
    }
    else
        RETAILMSG(1,(TEXT("DMAC: Interrupt initialize successfully SYSINTR = %d...\r\n"), dma_sys_intr));

    pDMAGlobals->gDmacThreadReadyEvent =  CreateEvent(NULL, FALSE, FALSE, NULL);
    pDMAGlobals->gDmacIntrThread = 
        CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) DmacIntrThread, NULL, 0, NULL);
    if ( pDMAGlobals->gDmacIntrThread == NULL ) 
    {		
        return NULL;
    }
    SetThreadPriority( pDMAGlobals->gDmacIntrThread, THREAD_PRIORITY_TIME_CRITICAL );
	WaitForSingleObject(pDMAGlobals->gDmacThreadReadyEvent, INFINITE);
    //
    // Initialize DMAC hardware
    // This will also stop any ongoing DMA activity
    //
	pDMAGlobals->hDMAEvent[0] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_0);
	pDMAGlobals->hDMAEvent[1] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_1);
	pDMAGlobals->hDMAEvent[2] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_2);
	pDMAGlobals->hDMAEvent[3] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_3);
	pDMAGlobals->hDMAEvent[4] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_4);
	pDMAGlobals->hDMAEvent[5] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_5);
	pDMAGlobals->hDMAEvent[6] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_6);
	pDMAGlobals->hDMAEvent[7] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_7);
	pDMAGlobals->hDMAEvent[8] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_8);
	pDMAGlobals->hDMAEvent[9] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_9);
	pDMAGlobals->hDMAEvent[10] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_10);
	pDMAGlobals->hDMAEvent[11] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_11);
	pDMAGlobals->hDMAEvent[12] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_12);
	pDMAGlobals->hDMAEvent[13] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_13);
	pDMAGlobals->hDMAEvent[14] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_14);
	pDMAGlobals->hDMAEvent[15] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_15);
	pDMAGlobals->hDMAEvent[16] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_16);
	pDMAGlobals->hDMAEvent[17] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_17);
	pDMAGlobals->hDMAEvent[18] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_18);
	pDMAGlobals->hDMAEvent[19] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_19);
	pDMAGlobals->hDMAEvent[20] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_20);
	pDMAGlobals->hDMAEvent[21] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_21);
	pDMAGlobals->hDMAEvent[22] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_22);
	pDMAGlobals->hDMAEvent[23] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_23);
	pDMAGlobals->hDMAEvent[24] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_24);
	pDMAGlobals->hDMAEvent[25] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_25);
	pDMAGlobals->hDMAEvent[26] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_26);
	pDMAGlobals->hDMAEvent[27] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_27);
	pDMAGlobals->hDMAEvent[28] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_28);
	pDMAGlobals->hDMAEvent[29] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_29);
	pDMAGlobals->hDMAEvent[30] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_30);
	pDMAGlobals->hDMAEvent[31] = CreateEvent(NULL,FALSE,FALSE,DMA_CHANNEL_31);


    GdeDmacEnableInterrupt();
    Sleep(10);
	SetEvent(hFirstTime);  // Signal that GDE Setup has successfully completed.
    RETAILMSG(1,(TEXT("XllpDmacInit success.\r\n")));    
	NKDbgPrintfW(TEXT("XllpDmacInit success.\r\n"));
    return pDmacHandle;    
}

/******************************************************************************
XLLP_DOC_HDR_BEGIN

  Function Name: GdeDmaAllocChannel

  Description: GdeDmacAllocChannel is used to obtain an available channel in 
  			   the system.  The channel that is allocated must then be used to
  			   bind a service routine to the operating system such that all 
  			   interrupts that occur on the channel will be routed to the bound
  			   service routine.  Once the channel is done transferring data, it
  			   can be freed by using GdeDmacFreeChannel.
  
  Global Registers Modified: None 

  Input Arguments:
	aChannelPriority: Specifies the priority of the channel reqested
		                 
  Output Arguments:
	pChannel: Holds the available DMA channel assigned to the calling device 
			  driver.  DMA channels range is from 0-31.   
  Return Value: 
	XLLP_STATUS_SUCCESS: Returned when a channel is available and assigned to caller
	XLLP_NO_DMA_CHANNELS_AVAILABLE: Returned when there is no available channel
									to be assigned 

XLLP_DOC_HDR_END
*******************************************************************************/
XLLP_STATUS_T	GdeDmacAllocChannel(
			   		 			  P_XLLP_DMAC_CHANNEL_T        pChannel,
			     	 			  XLLP_DMAC_CHANNEL_PRIORITY_T aChannelPriority
			     	 			  )
{
	XLLP_DMAC_CHANNEL_T i;
	XLLP_DMAC_CHANNEL_T aChannel;

#ifdef BSP_NOWLAN
#ifdef OSV_PPC
        // Reserve Channel 3 and 14 for WLAN
       
        pDMAGlobals->pArrayChannel[XLLP_DMAC_CHANNEL_3] = 1;
        pDMAGlobals->pArrayChannel[XLLP_DMAC_CHANNEL_14] = 1;
#endif
#endif

	switch(aChannelPriority)
	{
		case XLLP_DMAC_CHANNEL_PRIORITY_HIGH:
			{
				for (i=0; i < aPrioritySetCount; i++ )
				{
					aChannel = ChannelPriorityHigh[i];			 
					if (pDMAGlobals->pArrayChannel[aChannel] == 0)
					{
						pDMAGlobals->pArrayChannel[aChannel] = 1;   // Set this channel to InUse
						__try
						{
						    *pChannel = aChannel;
						}
						 __except(EXCEPTION_EXECUTE_HANDLER)
                                    {
                                        RETAILMSG( 1, ( _T("[DMA]XLLP_DMAC_CHANNEL_PRIORITY_HIGH Exception!") ) );
						    ASSERT(FALSE);
						    return XLLP_STATUS_WRONG_PARAMETER;
                                     }
						return (XLLP_STATUS_SUCCESS);        // Return no error
					}
				}	
				break;
			}
		case XLLP_DMAC_CHANNEL_PRIORITY_MEDIUM:
			{
				for (i=0; i < aPrioritySetCount; i++ )
				{
					aChannel = ChannelPriorityMedium[i];				
					if (pDMAGlobals->pArrayChannel[aChannel] == 0)
					{
						pDMAGlobals->pArrayChannel[aChannel] = 1;   // Set this channel to InUse
						__try
						{
							*pChannel = aChannel;
						}
						__except(EXCEPTION_EXECUTE_HANDLER)
                                    {
                                        RETAILMSG( 1, ( _T("[DMA]XLLP_DMAC_CHANNEL_PRIORITY_MEDIUM Exception!") ) );
						    ASSERT(FALSE);
						    return XLLP_STATUS_WRONG_PARAMETER;
                                     }
						return (XLLP_STATUS_SUCCESS);        // Return no error
					}
				}	
				break;
			}
		case XLLP_DMAC_CHANNEL_PRIORITY_LOW:
			{
				for (i=0; i < aPrioritySetCount; i++ )
				{
					aChannel = ChannelPriorityLow[i];				
					if (pDMAGlobals->pArrayChannel[aChannel] == 0)
					{
						pDMAGlobals->pArrayChannel[aChannel] = 1;   // Set this channel to InUse
						__try
						{
							*pChannel = aChannel;
						}
						__except(EXCEPTION_EXECUTE_HANDLER)
                                    {
                                        RETAILMSG( 1, ( _T("[DMA]XLLP_DMAC_CHANNEL_PRIORITY_LOW Exception!") ) );
						    ASSERT(FALSE);
						    return XLLP_STATUS_WRONG_PARAMETER;
                                     }
						return (XLLP_STATUS_SUCCESS);        // Return no error
					}
				}	
				break;
			}
		case XLLP_DMAC_CHANNEL_PRIORITY_LOWEST:
			{
				for (i=0; i < aPrioritySetCount; i++ )
				{
					aChannel = ChannelPriorityLowest[i];			
					if (pDMAGlobals->pArrayChannel[aChannel] == 0)
					{
						pDMAGlobals->pArrayChannel[aChannel] = 1;   // Set this channel to InUse
						__try
						{
							*pChannel = aChannel;
						}
						__except(EXCEPTION_EXECUTE_HANDLER)
                                    {
                                        RETAILMSG( 1, ( _T("[DMA]XLLP_DMAC_CHANNEL_PRIORITY_LOWEST Exception!") ) );
						    ASSERT(FALSE);
						    return XLLP_STATUS_WRONG_PARAMETER;
                                     }
						return (XLLP_STATUS_SUCCESS);        // Return no error
					}
				}	
				break;
			}
	}

	//
	// If we got this far, that means no channel was available for
	// the specified channel priority set. So look for any available
	// channel and return it
	// 
	for (i=0; i < XLLP_DMAC_CHANNEL_NUM; i++ )
	{
		if (pDMAGlobals->pArrayChannel[i] == 0)
		{
			pDMAGlobals->pArrayChannel[i] = 1;      // Set this channel to InUse
			__try
			{
				*pChannel = i;
			}
			__except(EXCEPTION_EXECUTE_HANDLER)
			{
				RETAILMSG( 1, ( _T("[DMA]GdeDmacAllocChannel Exception!") ) );
				ASSERT(FALSE);
				return XLLP_STATUS_WRONG_PARAMETER;
			}
			return (XLLP_STATUS_SUCCESS);    // Return no error
		}
	}	
	return XLLP_STATUS_NO_DMA_CHANNEL_AVAILABLE;	// No DMA channel is free
}


/******************************************************************************
XLLP_DOC_HDR_BEGIN

  Function Name: GdeDmacFreeChannel

  Description: GdeDmacFreeChannel is used to free a previously obtained channel
  			   back into the free channels pool in the system.  A channel that 
  			   is freed automatically becomes available for allocation when needed,
  			   and all interrupts that were previously being generated to this 
  			   channel will be disconnected.  
  			   
  Global Registers Modified: 
  	DMA request to channel map register, DRCMRx 

  Input Arguments:
	aChannel: Channel to be freed and made available for other users.
	aDeviceDrcmr: Specifies the device that was using the channel to be freed.  Valid
			 	  inputs are elements of type XLLP_DMAC_DRCMR_T, otherwise is invalid.
	                 
  Output Arguments:
  	None
  Return Value: 
	None 

XLLP_DOC_HDR_END
*******************************************************************************/
void GdeDmacFreeChannel(
						XLLP_DMAC_CHANNEL_T       aChannel,
						XLLP_DMAC_DRCMR_T         aDeviceDrcmr
					    )
{
	/* Verify if channel is currently set as InUse */
	if (pDMAGlobals->pArrayChannel[aChannel] == 1)
	{
		pDMAGlobals->pArrayChannel[aChannel] = (XLLP_DMAC_CHANNEL_T)0; /* Free this channel*/
	
		/* UnMap device from channel */
		if (aDeviceDrcmr != XLLP_DMAC_MEM2MEM_MOVE)
		{
			XllpDmacUnMapDeviceToChannel(pDmacHandle, aDeviceDrcmr, aChannel);
		}
	}
}

/******************************************************************************
XLLP_DOC_HDR_BEGIN

  Function Name:GdeDmacFillLinkedDesc

  Description: XllpDmacFillLinkedDesc is used to setup a descriptor or chained 
  			   descriptors for DMA transfer operations. To setup a descriptor 
  			   (ie. no chaining), the pointer to the next descriptor pNextDesc 
  			   is expected to be zero, otherwise pNextDesc expected to be a 
  			   valid descriptor pointer.  Users wanting to chain multiple 
  			   descriptors will call this function to accomplish that task.
  			   
  Global Registers Modified: 
	None
		
  Input Arguments:
	pDesc: Hold the pointer to the descriptor to be configured, cannot be a 
		   null pointer.
	pNextDesc: Holds the pointer to the next descriptor used in the DMA transfer
			   process after completely transferring data in the current descriptor
			   pDesc if the channel is not programmed to be stop.  pNextDesc can 
			   be a null pointer only if this descriptor is not meant to be chained.
	aStopContinue:  Specifies whether or not to configure this descriptor to stop
				    the channel after completely transferring data in this descriptor.
	aBranch: Specifies whether to configure this descriptor to enable or disable 
			 the descriptor branching mechanism.  Valid values are element of type
			 XLLP_DMAC_DESC_BRANCH_T (1 or 0).
	aSrcAddr: Holds the source address for this descriptor, cannot be null.
	aTargetAddr: Holds the target address for this descriptor, cannot be null.
	pCmd: Holds the commands for this descriptor.  Users are required to initialize 
		  the various fields of pCmd data structure before making this call.
	                 
  Output Arguments:
  	None
  Return Value: 
	None 

XLLP_DOC_HDR_END
*******************************************************************************/
void GdeDmacFillLinkedDesc(
						   P_XLLP_DMAC_DESCRIPTOR_T pDesc,
						   P_XLLP_DMAC_DESCRIPTOR_T pNextDescPhyAddr,
						   XLLP_DMAC_DESC_ENABLE_T  aStopContinue,
						   XLLP_DMAC_DESC_BRANCH_T  aBranch,
						   XLLP_UINT32_T            aSrcAddr,
						   XLLP_UINT32_T            aTargetAddr,
						   XLLP_DMAC_COMMAND_T*     pCmd
						  )
{
	XLLP_VUINT32_T aTargetValue;
	XLLP_UINT32_T aCommand;
	XLLP_VUINT32_T aNextDesc;

	if((!pDesc)||(!pCmd))
	{
		RETAILMSG( 1, ( _T("[DMA]GdeDmacFillLinkedDesc invalid parameters!") ) );
		return;
	}
	
	/* Construct command value from pCmd  */
	aCommand =  (XLLP_UINT32_T)(
								( pCmd->aLen) | ((pCmd->aWidth) << XLLP_BIT_FIELD_14)|
								((pCmd->aSize) << XLLP_BIT_FIELD_16)      |
								((pCmd->aEndian) << XLLP_BIT_FIELD_18)    | 
// ?? Not in MH DevMan			((pCmd->aFlyByT) << XLLP_BIT_FIELD_19)    |
// ?? Not in MH DevMan			((pCmd->aFlyByS) << XLLP_BIT_FIELD_20)    |
								((pCmd->aEndIrqEn)   << XLLP_BIT_FIELD_21)|
								((pCmd->aStartIrqEn) << XLLP_BIT_FIELD_22)|
// ?? Not in MH DevMan			((pCmd->aAddrMode)   << XLLP_BIT_FIELD_23)|
// ?? Not in MH DevMan			((pCmd->aCmpEn)   << XLLP_BIT_FIELD_25)   |
								((pCmd->aFlowTrg) << XLLP_BIT_FIELD_28)   |
								((pCmd->aFlowSrc) << XLLP_BIT_FIELD_29)   |
								((pCmd->aIncTrgAddr) << XLLP_BIT_FIELD_30)|
								((pCmd->aIncSrcAddr) << XLLP_BIT_FIELD_31)
							   );	   	

	/* Clear reserved bit fields of DDADR */
	aNextDesc = (XLLP_UINT32_T)pNextDescPhyAddr;  
	aNextDesc = (XLLP_UINT32_T)(aNextDesc & XLLP_DMAC_DDADR_RESERVED_MASK);
	aTargetValue = (XLLP_UINT32_T)(aNextDesc + (aBranch<<XLLP_BIT_FIELD_1) + aStopContinue);

	/* Fill descriptor entries            */
	pDesc->ddadr = (XLLP_UINT32_T)(aNextDesc) + (aBranch<<XLLP_BIT_FIELD_1) + aStopContinue;
	pDesc->dsadr = (XLLP_UINT32_T)aSrcAddr;
	pDesc->dtadr = (XLLP_UINT32_T)aTargetAddr;
	pDesc->dcmd  = (XLLP_UINT32_T)aCommand;

}

//******************************************************************************
//
// Function Name: DmacIntrThread
//
// Description: The IST for DMA Controller interrupt.
//  			   
//  
// Input Arguments:
//	
//	                 
// Output Arguments:
//  	
//
// Return Value: 
//	None 
//
// Notes: Calls the XllpDmacIntHandler which does the guts of the work
//
//*******************************************************************************
INT WINAPI DmacIntrThread
(
    void
)
{
	DWORD tmpDINT;
	//DWORD EventData;
	int i;
    XLLP_VUINT32_T  *pDCSR ;
    XLLP_VUINT32_T  tmpDCSR;
    XLLP_VUINT32_T  tmpDcsrClear;    

	SetEvent(pDMAGlobals->gDmacThreadReadyEvent);

    while (TRUE)
    {
		
	    WaitForSingleObject(pDMAGlobals->gDmacIntrEvent, INFINITE);
		// DMA interrupts are currently masked.  This routine will not be interrupted by another DMA interrupt.
		tmpDINT = pDmacHandle->dint;
        for ( i=0; i<XLLP_DMAC_CHANNEL_NUM; i++ )
        {
            if (tmpDINT & (1u << i))
            {               
				// Provide the Waiting Object the current value of the channel Status Register.
				//    where data describing the specific cause of the interrupt is held. The
				//    Dma Engine clears the Status register when it acknowledges the interrupt.
				SetEventData(pDMAGlobals->hDMAEvent[i], pDmacHandle->dcsr[i]);
				// Acknowledge the given interrupt channel
				//pDmacHandle->DCSR[i] |= (0x1 << 2);  // Orig.
                pDCSR = &(pDmacHandle->dcsr[i]);
                tmpDCSR = *pDCSR;
                // Isolate all writeable bits, including those that
                // both report and clear a status.
                tmpDcsrClear = (tmpDCSR & XLLP_DCSR_WRITABLES_MSK);
                // Stop intr is not cleared by a simple write-back.  Must also
                //  restart the DMA (not done in ISR)
                if (tmpDCSR & XLLP_DMAC_DCSR_STOP_INTR)
                    tmpDcsrClear &= ~(XLLP_DMAC_DCSR_STOP_IRQ_EN);
                // Clear the status
                *pDCSR = tmpDcsrClear;
				// Signal the waiting thread
				SetEvent(pDMAGlobals->hDMAEvent[i]); // should search this list in priority order instead of linearly.
			// Stop searching if there are no more threads to signal
			if ((unsigned)i >= tmpDINT)
				break;
			}
		}
		// Now that we have SetEvent on all known interrupt source, we can re-enable DMA interrupts.
		InterruptDone(dma_sys_intr);
    }
	
    return XLLP_STATUS_SUCCESS;
}


BOOL XllpDmacAcquireMutex
(    
    HANDLE  *hDmacMutex,
    DWORD   timeout
)
{    
    //
    // Create the mutex for protecting access to shared data structures (channel array map)
    // Need to be acquired before calling XllpAllocate/FreeChannel
    //
    if ((*hDmacMutex = CreateMutex(NULL, FALSE, DMAC_MUTEX_NAME)) == NULL)
    {        
        return FALSE;
    }

    if (WaitForSingleObject(*hDmacMutex, timeout) == WAIT_TIMEOUT)
    {
        CloseHandle(*hDmacMutex);
        return FALSE;
    }

    return TRUE;
}

VOID XllpDmacFreeMutex
(
    HANDLE  hDmacMutex
)
{
    ReleaseMutex(hDmacMutex);
    CloseHandle(hDmacMutex);
}

void XllpDmacDumpStatus( XLLP_DMAC_CHANNEL_T aChannel )
{    

    //RETAILMSG(1,(TEXT("DMA:>DumpStatus DmaChan=%02d Src=0x%08x Tgt=0x%08x Cmd=0x%08x Dcsr=0x%08x DINT=0x%08x \r\n"),aChannel, pDmacHandle->DDG[aChannel].DSADR, pDmacHandle->DDG[aChannel].DTADR, pDmacHandle->DDG[aChannel].DCMD, pDmacHandle->DCSR[aChannel], pDmacHandle->DINT ));
    //RETAILMSG(1,(TEXT("DMA:>DrcmrRx=0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x \r\n"), pDmacHandle->DRCMR1[48], pDmacHandle->DRCMR1[50],pDmacHandle->DRCMR1[52],pDmacHandle->DRCMR1[54],pDmacHandle->DRCMR1[56],pDmacHandle->DRCMR1[58],pDmacHandle->DRCMR1[60] ));
    //RETAILMSG(1,(TEXT("DMA:>DrcmrTx=0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x \r\n"), pDmacHandle->DRCMR1[49], pDmacHandle->DRCMR1[51],pDmacHandle->DRCMR1[53],pDmacHandle->DRCMR1[55],pDmacHandle->DRCMR1[57],pDmacHandle->DRCMR1[59],pDmacHandle->DRCMR1[61] ));
}


#define	MASK_ICMR_DMAC		( 1 << XLLP_INTC_S_DMA )

void GdeDmacEnableInterrupt
(
)
{
	XllpWriteINTCReg(XLLP_INTC_ICMR, MASK_ICMR_DMAC | XllpReadINTCReg(XLLP_INTC_ICMR ) );
}

void GdeDmacDisableInterrupt
(
)
{
	XllpWriteINTCReg(XLLP_INTC_ICMR, ~MASK_ICMR_DMAC | XllpReadINTCReg(XLLP_INTC_ICMR ) );
}



//******************************************************************************
//
// Function Name: OSMemAlloc
//
// Description: Allocates a block of memory
//  			   
//  
// Input Arguments:
//	    numBytes:   Number of bytes to allocate
//	                 
// Output Arguments:
//  	
//
// Return Value: 
//	    void*:      Pointer to allocated memory. NULL if unsuccessful.
//
// Notes:
//      Memory allocated by this call is aligned on page boundary (4K on XScale)
//
//*******************************************************************************
VOID* OSMemAlloc
(
    UINT32   numBytes
)
{    
    return VirtualAlloc(0, numBytes, MEM_COMMIT, PAGE_READWRITE | PAGE_NOCACHE);
}

//******************************************************************************
//
// Function Name: OSMemFree
//
// Description: Frees a previously allocated block of memory
//  			   
//  
// Input Arguments:
//	    VOID* memPtr:   pointer to memory to deallocate
//	                 
// Output Arguments:
//  	
//
// Return Value: 
//	    
//
// Notes:
//      
//
//*******************************************************************************
VOID OSMemFree
(
    VOID*           memPtr
)
{    
    VirtualFree(memPtr, 0, MEM_RELEASE);
}

//******************************************************************************
//
// Function Name: OSGetMaxPages
//
// Description: Returns max number of physical pages that may be occupied by a user buffer
//  			   
//  
// Input Arguments:
//	    pBuffer:        Virtual address to user buffer
//      bufferLength:   Length of user buffer
//	                 
// Output Arguments:
//  	
//
// Return Value: 
//	    Maximum number of physical pages that can be spanned by user buffer
//
// Notes:
//      WinCe generally allocates memory aligned on page boundaries.
//
//*******************************************************************************
XLLP_UINT32_T OSGetMaxPages
(
    XLLP_UINT8_T    *pBuffer,
    XLLP_UINT32_T   bufferLength
)
{
    return ADDRESS_AND_SIZE_TO_SPAN_PAGES(pBuffer, bufferLength);
}

//******************************************************************************
//
// Function Name: OSLockPhysicalPages
//
// Description: Locks physical pages representing a virtual address space into memory.
//              Returns information about locked pages to user
//  			   
//  
// Input Arguments:
//	    VOID*  virtualAddress:  Pointer to virtual address space to lock
//      UINT32 numBytesTolock;  Number of bytes of linear address sace to lock
//      UINT32 osFlags:         OS specific flags.
//	                 
// Output Arguments:
//      UINT32 *pageAddresses:  Array in which list of all physical pages representing 
//                              buffer is returned
//
// Return Value: 
//      TRUE:   if successful
//      FALSE:  otherwise	    
//
// Notes:
//      Invokes LockPages on WinCE which is supported for .NET, PocketPC and SmartPhone
//      platforms
//
//*******************************************************************************
BOOL OSLockPhysicalPages
(
    VOID*           virtualAddress,
    XLLP_UINT32_T   numBytesToLock,
    XLLP_UINT32_T   *pageAddresses,
    XLLP_UINT32_T   osFlags
)
{
    return LockPages(virtualAddress, numBytesToLock, pageAddresses, osFlags);
}

//******************************************************************************
//
// Function Name: OSUnlockPhysicalPages
//
// Description: Unlocks previously locked physical pages representing a virtual 
//              address space into memory.
//              
// Input Arguments:
//	    VOID*  virtualAddress:      Pointer to virtual address space to lock
//      UINT32 numBytesToUnlock;    Number of bytes of linear address sace to unlock
//	                 
// Output Arguments:
//
// Return Value: 
//      TRUE:   if successful
//      FALSE:  otherwise	    
//
// Notes:
//      Invokes UnlockPages on WinCE which is supported for .NET, PocketPC and SmartPhone
//      platforms
//
//*******************************************************************************
BOOL OSUnlockPhysicalPages
(
    VOID*           virtualAddress,
    XLLP_UINT32_T   numBytesToUnlock
)
{
    return UnlockPages(virtualAddress, numBytesToUnlock);
}

//=============================================================================
//=========================Working DMA Sample Code ============================
//================================ Start ======================================
// 
// To validate the "DMA Engine" the following two routines were called in the 
// Keyboard IST when the "0" key was pressed. Diagnostic output via the function 
// NKDbgPrintfW(..) shows the  Virtual and Physical addresses used to setup and 
// run the Memory-to-Memory DMA transfer
// 
//		XllpDmacInit(void);
//		XllpDmacTest(void);
//
//			Note: XllpDmacTest was added to dma.def for validation testing.
//
//=============================================================================
//=============================================================================


P_XLLP_UINT8_T			pDescriptor0;
P_XLLP_UINT8_T			pDescriptor1;
P_XLLP_UINT8_T			pSrcMemory;
P_XLLP_UINT8_T			pDstMemory;
P_XLLP_UINT8_T			pExtMemory;

volatile DMA_GLOBALS *pDMAGlobalsThread = NULL;
volatile P_XLLP_DMAC_T	pDmacHandleThread = NULL;
volatile P_XLLP_DMAC_T	pDmacHandleTest = NULL;


//******************************************************************************
//
// Function Name: DmacTestThread
//
// Description: Test thread which waits for the channel specific test object
//			    to be signaled by the DMA IST, DmacIntrThread.
//  			   
//  
// Input Arguments:
//	
//	                 
// Output Arguments:
//  	
//
// Return Value: 
//	None 
//
//
//*******************************************************************************
INT WINAPI DmacTestThread
(
    void *Channel
)
{
    PHYSICAL_ADDRESS RegPA;
    
    XLLP_VUINT32_T  tmp_dint;
    XLLP_VUINT32_T  tmpDCSR;
    XLLP_UINT32_T	idxChannel;
    //void *			EventHandle;
    HANDLE			EventHandle;
    XLLP_UINT32_T	i;
    XLLP_UINT32_T	EventData;
    //XLLP_UINT32_T	LastError;
    P_XLLP_INT8_T			pByteSrc;
    P_XLLP_INT8_T			pByteDst;
    _TCHAR			EventName[20];
    HANDLE			hSharedMap;


	idxChannel = (unsigned int)(Channel);
	NKDbgPrintfW(TEXT("idxChannel = 0x%X\r\n"), idxChannel);
	
    RETAILMSG(1,(TEXT("DmacTestThread .....Initialized\r\n")));

	// Compose the name of the channel event for use with CreateEvent(...) below.
	_stprintf(EventName, TEXT("DMA_CHANNEL_%d"), idxChannel);
	NKDbgPrintfW(TEXT("EventName = %s\r\n"), EventName);

	// Memory mapped file for sharing DMA Globals information.
	hSharedMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
									0, sizeof(DMA_GLOBALS), GDE_SHARED_FILENAME );
	// Memory mapped file should exist from setup in GDE_Init() .
	if( ERROR_ALREADY_EXISTS != GetLastError() )
	{
		NKDbgPrintfW(TEXT("DmacTestThread. No existing MemMapFile . \r\n"));
		return FALSE;	// Memory mapped file set failed
	}
	// Get a valid process pointer to the buffer mapped above.
	pDMAGlobalsThread = (DMA_GLOBALS *)MapViewOfFile( hSharedMap, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
	if( !pDMAGlobalsThread )
	{
		NKDbgPrintfW(TEXT("DmacTestThread. MapViewOfFile failed . \r\n"));
		return FALSE;	// Memory mapped file set failed.
	}

	// Map the DMAC registers.
	pDmacHandleThread = NULL;
	
        RegPA.QuadPart = MONAHANS_BASE_REG_PA_DMAC;
        pDmacHandleThread = (P_XLLP_DMAC_T) MmMapIoSpace(RegPA, sizeof(XLLP_DMAC_T), FALSE);

	if (pDmacHandleThread == NULL)
	{				
		NKDbgPrintfW(TEXT("pDmacHandleThread mapping FAILED...\r\n"));
		return 0;  // 
	}
	// Get event handle for this channel. Note that using the numerical event
	// value, pDMAGlobalsThread->hDMAEvent[idxChannel],  stored in the DMA_Globls
	// struture will in general only work for threads that belong to the Device 
	// Manager (DM) process which contains the IST ( DmacIntrThread ) for the DMA Engine.  
	//
	// Drivers or applications that belong to a different process must obtain
	// the handle value by using the event name as shown below. A general solution
	// will always use the event name.
	// Note. For this implementation of WinCE is happens that the event handle is the
	//		 same in each process. There is no guarantee this will continue to be the
	//		 in future implementations.

	//EventHandle = pDMAGlobalsThread->hDMAEvent[idxChannel];
	//NKDbgPrintfW(TEXT("EventHandle in Test Thread = 0x%08X...\r\n"), EventHandle);
	//if (EventHandle == NULL)
	//{
	//	NKDbgPrintfW(TEXT("EventHandle Zero, NOT Initialized...\r\n"));
	//	return 0;  // 
	//}

	EventHandle = CreateEvent(NULL,FALSE,FALSE, EventName);
	NKDbgPrintfW(TEXT("EventHandle in Test Thread = 0x%08X...\r\n"), EventHandle);
	if (EventHandle == NULL)
	{
		NKDbgPrintfW(TEXT("EventHandle (Named) is Zero...\r\n"));
		return 0;  // 
	}

    while (TRUE)
    {
		NKDbgPrintfW(TEXT("DmacTestThread BEFORE WaitFor...\r\n"));
		// The DMA Engine will after processing an interrupt.
	    WaitForSingleObject(EventHandle, INFINITE);
		NKDbgPrintfW(TEXT("DmacTestThread AFTER WaitFor...\r\n"));
		// Get the DCSR value for the channel that interrupted.
		EventData = GetEventData(EventHandle);
		NKDbgPrintfW(TEXT("GetEventData in Test Thread = 0x%08X...\r\n"), EventData);

		tmp_dint = pDmacHandleThread->dint;	// Get the current interrupt bits.
		tmpDCSR  = pDmacHandleThread->dcsr[idxChannel];

        RETAILMSG(1,(TEXT("DmacIntHandler: chan=%d DINT=0x%08x DCSR=0x%08x DCMD=0x%08x\r\n"), idxChannel, tmp_dint, tmpDCSR, pDmacHandleThread->ddg[idxChannel].dcmd ));

		// Display Source/Destination Data
		pByteSrc = pSrcMemory;
		pByteDst = pDstMemory;
		for(i=0; i<32; i++)
		{
			NKDbgPrintfW(TEXT("\r\n..S-%x = 0x%X....\r\n"),pByteSrc, *pByteSrc);
			NKDbgPrintfW(TEXT("..D-%x = 0x%X....\r\n"),pByteDst, *pByteDst);
			pByteSrc++;
			pByteDst++;
		}

		// Free the channel. For channel allocation testing, comment out GdeDmacFreeChannel .

		GdeDmacFreeChannel(	idxChannel,  XLLP_DMAC_MEM2MEM_MOVE );

    }
    
    return XLLP_STATUS_SUCCESS;
}

//*******************************************************************************
//
//	Function Name: GdeDmacTest
//
//
//	Description: Setup a simple memory-to-memory transfer with the DMA hardware.
//
//
//*******************************************************************************

#define GDE_VIRT_BUFFER_DESCRIPTOR	GDE_BUFFER_VIRTUAL + 0x2000
#define GDE_VIRT_BUFFER_SRC			GDE_BUFFER_VIRTUAL + 0x2000 + 0x100
#define GDE_VIRT_BUFFER_DST			GDE_BUFFER_VIRTUAL + 0x2000 + 0x300

#define GDE_PHYS_BUFFER_DESCRIPTOR	GDE_BUFFER_PHYSICAL + 0x2000
#define GDE_PHYS_BUFFER_SRC			GDE_BUFFER_PHYSICAL + 0x2000 + 0x100
#define GDE_PHYS_BUFFER_DST			GDE_BUFFER_PHYSICAL + 0x2000 + 0x300

#define	TESTBUF_SIZE		0x100
#define TEST_SIZE_TOTAL		(2 * (sizeof(XLLP_DMAC_DESCRIPTOR_T) + TESTBUF_SIZE))

//XLLP_BOOL_T  XllpDmacTest( void )
XLLP_BOOL_T  GdeDmacTest( void )
{

	XLLP_DMAC_CHANNEL_T		Channel;
	P_XLLP_UINT8_T			pbDMATemp;
	P_XLLP_UINT8_T			pbPhyDMATemp;
    PHYSICAL_ADDRESS		PA;
	XLLP_UINT32_T			i;
	P_XLLP_INT8_T			pByteSrc;
	P_XLLP_INT8_T			pByteDst;
	HANDLE					gDmacIntrThread;
    DMA_ADAPTER_OBJECT		Adapter;

    P_XLLP_UINT8_T			pPhyDescriptor0;
    P_XLLP_UINT8_T			pPhyDescriptor1;
    P_XLLP_UINT8_T			pPhySrcMemory;
    P_XLLP_UINT8_T			pPhyDstMemory;
//d    P_XLLP_UINT8_T			pXlatPhyDescriptor;
//d    P_XLLP_UINT8_T			pXlatPhyDescriptor1;
//d    P_XLLP_UINT8_T			pXlatPhySrcMemory;
//d    P_XLLP_UINT8_T			pXlatPhyDstMemory;


	XLLP_DMAC_COMMAND_T		TestCmd;

	NKDbgPrintfW(TEXT("\r\nDMAC Test...\r\n"));
	
	// Initialize for this Process/Thread.
//	if( !XllpDmacInit() )
	if( NULL == ( pDmacHandleTest = GdeDmacInit()) )  
	{
			NKDbgPrintfW(TEXT("DmacTest-GdeDmacInit failed\r\n"));
			return XLLP_FALSE;
	}

	NKDbgPrintfW(TEXT("DmacTest...pDmacHandleTest = 0x%08x, pDmacHandle = 0x%08x \r\n"),
								  pDmacHandleTest,          pDmacHandle  );
	

	// Obtain a DMA channel
	NKDbgPrintfW(TEXT("\r\nObtain a channel\r\n"));

	if(XLLP_STATUS_SUCCESS != GdeDmacAllocChannel(  &Channel,  XLLP_DMAC_CHANNEL_PRIORITY_MEDIUM))
	{
			NKDbgPrintfW(TEXT("GdeDmacAllocChannel failed\r\n"));
			return XLLP_FALSE;
	}
	NKDbgPrintfW(TEXT("AllocChannel=%d \r\n"),Channel);

	//  Create a thread that waits for the above Channel event to be signaled.
    gDmacIntrThread = 
        CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) DmacTestThread, (void *)Channel, 0, NULL);
    if ( gDmacIntrThread == NULL ) 
    {		
		NKDbgPrintfW(TEXT("DTest--Create Test Thread Failed."));
        return (FALSE);
    }

    // Map DMA for a Memory-to-Memory Transfer. NOT needed for Mem2Mem transfers.
	XllpDmacMapDeviceToChannel(	  pDmacHandleTest,
							      XLLP_DMAC_MEM2MEM_MOVE,
								  Channel
						       );

    // Allocate blocks of virtual memory for Descriptors, Source & Destination.
	// DMA_GLOBALS. Not used for this test.

//-->
    // Map both DMA pages into the local address space.
    //
    Adapter.ObjectSize    = sizeof(DMA_ADAPTER_OBJECT);
    Adapter.InterfaceType = Internal;
    Adapter.BusNumber     = 0;

    pbDMATemp =  (P_XLLP_UINT8_T)HalAllocateCommonBuffer(&Adapter, TEST_SIZE_TOTAL , &PA, FALSE);
    if (!pbDMATemp)
    {
        DEBUGMSG(ZONE_ERROR, (TEXT("ERROR: pbDMATemp failed to allocate DMA buffer(s).\r\n")));
        return(FALSE);
    }

    pbPhyDMATemp = (BYTE *)PA.LowPart;
//--<

	pDescriptor0	= pbDMATemp;
	pPhyDescriptor0	= pbPhyDMATemp;

	pDescriptor1	= pDescriptor0		+ sizeof(XLLP_DMAC_DESCRIPTOR_T);
	pPhyDescriptor1	= pPhyDescriptor0	+ sizeof(XLLP_DMAC_DESCRIPTOR_T);

	pSrcMemory		= pDescriptor1		+ sizeof(XLLP_DMAC_DESCRIPTOR_T);
	pPhySrcMemory	= pPhyDescriptor1	+ sizeof(XLLP_DMAC_DESCRIPTOR_T);

	pDstMemory		= pSrcMemory		+ TESTBUF_SIZE;
	pPhyDstMemory	= pPhySrcMemory		+ TESTBUF_SIZE;




	NKDbgPrintfW(TEXT("pbDMATemp = 0x%X\r\n"), pbDMATemp);

	// Display Virtual and Physical Address Values.

	if (pbDMATemp)
    {
        // Save pointers to the virtual & physical addresses so the driver can access them.

		NKDbgPrintfW(TEXT("pDescriptor0    = 0x%X\r\n"), pDescriptor0);
		NKDbgPrintfW(TEXT("pPhyDescriptor0 = 0x%X\r\n"), pPhyDescriptor0);	
		NKDbgPrintfW(TEXT("pDescriptor1    = 0x%X\r\n"), pDescriptor1);
		NKDbgPrintfW(TEXT("pPhyDescriptor1 = 0x%X\r\n"), pPhyDescriptor1);
		NKDbgPrintfW(TEXT("pSrcMemory      = 0x%X\r\n"), pSrcMemory);
		NKDbgPrintfW(TEXT("pPhySrcMemory   = 0x%X\r\n"), pPhySrcMemory);
		NKDbgPrintfW(TEXT("pDstMemory      = 0x%X\r\n"), pDstMemory);
		NKDbgPrintfW(TEXT("pPhyDstMemory   = 0x%X\r\n"), pPhyDstMemory);

//d		pXlatPhyDescriptor  = (P_XLLP_UINT8_T)XllpDmacGetPhysicalAds(pDescriptor0);
//d		pXlatPhyDescriptor1 = (P_XLLP_UINT8_T)XllpDmacGetPhysicalAds(pDescriptor1);
//d		pXlatPhySrcMemory   = (P_XLLP_UINT8_T)XllpDmacGetPhysicalAds(pSrcMemory);
//d		pXlatPhyDstMemory   = (P_XLLP_UINT8_T)XllpDmacGetPhysicalAds(pDstMemory);

//d		NKDbgPrintfW(TEXT(" Xlat pDescriptor0 Phy Addr = 0x%X\r\n"), pXlatPhyDescriptor);
//d		NKDbgPrintfW(TEXT(" Xlat pDescriptor1 Phy Addr = 0x%X\r\n"), pXlatPhyDescriptor1);
//d		NKDbgPrintfW(TEXT(" Xlat pSrcMemory   Phy Addr = 0x%X\r\n"), pXlatPhySrcMemory);
//d		NKDbgPrintfW(TEXT(" Xlat pDstMemory   Phy Addr = 0x%X\r\n"), pXlatPhyDstMemory);

		NKDbgPrintfW(TEXT("sizeof(XLLP_DMAC_DESCRIPTOR_T) = 0x%X\r\n"), sizeof(XLLP_DMAC_DESCRIPTOR_T));
    }
	else
	{
		NKDbgPrintfW(TEXT("pbDMATemp VirtualCopy failed\r\n"));
		return XLLP_FALSE;
	}
	// Only one Descriptor for this test, so linking is not needed.

	//  Load data into the descriptor.
	NKDbgPrintfW(TEXT("\r\n...Load the descriptor-Format...\r\n"));

	TestCmd.aLen        = TESTBUF_SIZE - 0x10;
	TestCmd.aWidth      = XLLP_DMAC_WIDTH_0;
	TestCmd.aSize	    = XLLP_DMAC_RESERVED_SIZE;
	TestCmd.aEndian		= XLLP_FALSE;   // Little Endian.
// pkdebug. No FlyBy bits in Monahan.
//	TestCmd.aFlyByT		= XLLP_FALSE;	// Normal Transfer. No Fly by
//	TestCmd.aFlyByS		= XLLP_FALSE;	// Normal Transfer. No Fly by
	TestCmd.aEndIrqEn   = XLLP_TRUE;	// Interrupt when len = 0.
	TestCmd.aStartIrqEn = XLLP_FALSE;	// No Interrupt when Desc is loaded.
// ?? Yes Diagram, No Text in DevMan.	TestCmd.aAddrMode   = XLLP_FALSE;	// Src & Dst contains values for addresses.
// ?? Yes, No as above.	TestCmd.aCmpEn      = XLLP_FALSE;
	TestCmd.aFlowTrg    = XLLP_FALSE;
	TestCmd.aFlowSrc    = XLLP_FALSE;
	TestCmd.aIncTrgAddr = XLLP_TRUE;
	TestCmd.aIncSrcAddr = XLLP_TRUE;

	NKDbgPrintfW(TEXT("\r\n...Load the descriptor-Call...\r\n"));
	
	GdeDmacFillLinkedDesc(
						    (P_XLLP_DMAC_DESCRIPTOR_T)pDescriptor0,
						    (P_XLLP_DMAC_DESCRIPTOR_T)pPhyDescriptor1,
						    //(P_XLLP_DMAC_DESCRIPTOR_T)pXlatPhyDescriptor1,
						    XLLP_DMAC_DESC_STOP_CHANNEL,
						    XLLP_DMAC_DISABLE_DESC_BRANCH,
						    (XLLP_UINT32_T)pPhySrcMemory,
						    (XLLP_UINT32_T)pPhyDstMemory,
						    //(XLLP_UINT32_T)pXlatPhySrcMemory,
						    //(XLLP_UINT32_T)pXlatPhyDstMemory,
						    &TestCmd
						  );

	NKDbgPrintfW(TEXT("\r\n...Load the descriptor-Done...\r\n"));
	
    // Configure Channels to use Descriptors.
	NKDbgPrintfW(TEXT("\r\n...Configure a channel for Descriptors...\r\n"));
	NKDbgPrintfW(TEXT("DCSR[%d]  = 0x%X  ...\r\n"), Channel ,pDmacHandle->dcsr[Channel] );

	XllpDmacCfgChannelDescTransfer(	 pDmacHandleTest,
					    		     (P_XLLP_DMAC_DESCRIPTOR_T)pPhyDescriptor0,
								     Channel,
								   //XLLP_DMAC_DRCMR_T         aDeviceDrcmr,
								     XLLP_DMAC_MEM2MEM_MOVE
// ?? DALGN not in MH DevMan	     XLLP_DMAC_ALIGNMENT_OFF
				     	  		   );

	NKDbgPrintfW(TEXT("DDADR[%d] = 0x%X  ...\r\n"), Channel ,pDmacHandle->ddg[Channel].ddadr);
	NKDbgPrintfW(TEXT("DSADR[%d] = 0x%X  ...\r\n"), Channel ,pDmacHandle->ddg[Channel].dsadr);
	NKDbgPrintfW(TEXT("DTADR[%d] = 0x%X  ...\r\n"), Channel ,pDmacHandle->ddg[Channel].dtadr);
	NKDbgPrintfW(TEXT("DCMD [%d] = 0x%X  ...\r\n"), Channel ,pDmacHandle->ddg[Channel].dcmd);

    // Link Descriptors

	// Only one Descriptor, so linking is not needed.

	// Enable interrupts for the requested channel. Not Needed.

	// Put a Pattern in the Src memory. 

	NKDbgPrintfW(TEXT("\r\n...Initialize Src/Dst memory....\r\n"));

	pByteSrc = pSrcMemory;
	pByteDst = pDstMemory;

	for(i=0; i< 0x100; i++)
	{
		*pByteSrc++ = (XLLP_INT8_T)i;
		*pByteDst++ = 0x5A;
	}

	// Display Source/Destination Data

	pByteSrc = pSrcMemory;
	pByteDst = pDstMemory;
	for(i=0; i<16; i++)
	{
		NKDbgPrintfW(TEXT("\r\n..S-%x = 0x%X....\r\n"),pByteSrc, *pByteSrc);
		NKDbgPrintfW(TEXT("..D-%x = 0x%X....\r\n"),pByteDst, *pByteDst);
		pByteSrc++;
		pByteDst++;
	}

    // Start the Transfer.

	NKDbgPrintfW(TEXT("\r\n...The the M-M Xfer...\r\n"));

	XllpDmacStartTransfer(	pDmacHandleTest,
							Channel );

	// Completed 

	NKDbgPrintfW(TEXT("\r\n...Completed DMAC Test...\r\n"));
	
	return XLLP_TRUE;

}


